/*
 * Copyright 2012 the original author or authors.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package org.chacha.socket.server;

import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;

/**
 * 
 *	@author: hejing
 *	@date: 2012-11-15-上午09:38:04
 */
public class ChannelHelper {
	protected SocketChannel sc;
    protected ByteBuffer requestBB;
    private static int requestBBSize = 1024;
    private static int WriteCharBufferSize=1024;
    /**
     * 
     * @param sc
     * @param block   是否阻塞
     * @throws IOException
     */
	public ChannelHelper(SocketChannel sc,boolean block) throws IOException {
		this.sc = sc;
		sc.configureBlocking(block);
	}
    /**
     * 
     * @param sc
     * @param block   是否阻塞
     * @return
     * @throws IOException
     */
    public static ChannelHelper getInstance(SocketChannel sc,boolean block) throws IOException{
    	ChannelHelper ch=new ChannelHelper(sc,block);
    	ch.requestBB=ByteBuffer.allocate(requestBBSize);
    	return ch;
    }
    
    public SocketChannel getSocketChannel() {
    	return sc;
    }
    /**
     * 调整扩展buffer大小
     * @param remaining
     */
    protected void resizeRequestBB(int remaining) {
    	if (requestBB.remaining() < remaining) {
    	    //扩展buffer大小
    	    ByteBuffer bb = ByteBuffer.allocate(requestBB.capacity() * 2);
    	    requestBB.flip();
    	    bb.put(requestBB);
    	    requestBB = bb;
    	}
   }
    
    public int read() throws IOException {
    	//如果剩余空间小于5%，分配更大空间
    	resizeRequestBB(requestBBSize/20);
    	return sc.read(requestBB);
    }
    
    public ByteBuffer getReadBuf() {
    	return requestBB;
    }
    
    public int write(ByteBuffer src) throws IOException {
    	return sc.write(src);
    }
    
    public int write(String response,Charset cs) throws IOException{
		CharBuffer wcb = CharBuffer.allocate(WriteCharBufferSize);
		while(true){
			try{
				wcb.put(response);
				break;
			}catch(BufferOverflowException e){
				//动态分配内存
				assert(wcb.capacity() < (1 << 16));
				wcb = CharBuffer.allocate(wcb.capacity() * 2);
				continue;
			}
		}
		wcb.flip();
		ByteBuffer wbb=cs.encode(wcb);
		return write(wbb);
    }
    
    public long transferTo(FileChannel fc, long pos, long len) throws IOException {
    	return fc.transferTo(pos, len, sc);
    }

    /*
     * Close the underlying connection.
     */
    public void close() throws IOException {
    	sc.close();
    }
}
